package com.tyq.auth.oauth2;

import com.tyq.auth.security.access.MyAccessDecisionManager;
import com.tyq.auth.security.handler.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;

import javax.annotation.Resource;

/**
 * 如果要在把授权服务器中提供其他接口，则需要配置资源服务器
 *
 * @author 谭永强
 * @date 2024-06-03
 */
@Configuration
@EnableResourceServer
public class Oauth2ResourceServerConfig extends ResourceServerConfigurerAdapter {

    /**
     * 资源ID
     */
    private final static String RESOURCE_ID = "order";
    @Resource
    private TokenStore tokenStore;
    @Resource
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Resource
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    @Resource
    private MyAccessDeniedHandler myAccessDeniedHandler;
    @Resource
    private MyLogoutSuccessHandler myLogoutSuccessHandler;
    @Resource
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;
    @Resource
    private MyAccessDecisionManager myAccessDecisionManager;

    /**
     * 重写安全配置信息
     *
     * @param http 安全配置
     * @throws Exception 异常
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                //表单登录
                .formLogin()
                //将`/login`请求认为是登录请求，该url必须与前端登录页面发送的请求一致，接收到该请求后就会去执行`UserDetailsServiceImpl`的登录逻辑
                .loginProcessingUrl("/login")
                //自定义登录成功处理器，不能与successForwardUrl共存
                .successHandler(myAuthenticationSuccessHandler)
                //自定义登录失败处理器，不能与failureForwardUrl共存
                .failureHandler(myAuthenticationFailureHandler)
                .and()
                //配置退出功能
                .logout()
                //自定义退出登录成功处理器
                .logoutSuccessHandler(myLogoutSuccessHandler)
                .and()
                .exceptionHandling()
                .and()
                //请求拦截器
                .authorizeRequests()
                //设置不需要认证的请求
                .antMatchers("/login.html", "/error.html", "/favicon.ico").permitAll()
                .antMatchers("/oauth/**").permitAll()
                //所有请求需要认证
                .anyRequest().authenticated()
                //自定义访问决策管理器
                .accessDecisionManager(myAccessDecisionManager)
                .and()
                //关闭cors防护
                .cors().disable()
                //关闭csrf防护
                .csrf().disable()
                //使用JWT，关闭session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources
                //资源ID(可选)，但是此处必须指定，否则请求接口会出现'异常：Invalid token does not contain resource id (oauth2-resource)'
                .resourceId(RESOURCE_ID)
                //自定义未认证请求处理器
                .authenticationEntryPoint(myAuthenticationEntryPoint)
                //自定义无权限请求处理器
                .accessDeniedHandler(myAccessDeniedHandler)
                .tokenStore(tokenStore);
    }
}
